/*
 * ServerService.cpp
 *
 *  Created on: 03/06/2011
 *      Author: wadi
 */

#include "serverservice.h"
#include <iostream>
#include "../common/comm/lock.h"
/**
 *
 */
ServerService& ServerService::getInstance() {
  static ServerService instance; // guaranteed to be destroyed, instantiated on first use.
  return instance;
}

/**
 *
 */
ServerService::ServerService() :
	        logger_(log4cxx::Logger::getLogger("client.media.capture_workspace_x11_alsa_impl")),
	        handler(0),
	        opened(false) {
}

/**
 *
 */
ServerService::~ServerService() {
  if (opened)
    stop();
}

/**
 *
 */
void ServerService::stop() {
  if (opened) {
      LOG4CXX_DEBUG(logger_, "stopping");
      socket.closeSocket();
      opened = false;
  }
}

/**
 * @return True if can connect to host, false otherwise
 */
bool ServerService::initComunication(std::string url, int port) {
  if (!opened) {
      bool success = socket.open();
      success = this->socket.connectTo(url, port);
      if (success) {
          opened = true;
          LOG4CXX_DEBUG(logger_, "successfully connected to: " << url << ":" << port);
          LOG4CXX_DEBUG(logger_, "starting the thread");
          start();
      } else {
          LOG4CXX_DEBUG(logger_, "unable to connect to: " << url << ":" << port);
      }
  }

  return opened;
}


void ServerService::findAllShows() {
  std::vector<char> request = protocol.buildFindAllShowsRequest();
  socket.escribir(&request.at(0), request.size());
}


void ServerService::login(std::string username, std::string password) {
  std::vector<char> loginRequest = protocol.buildLoginRequest(username, password);
  socket.escribir(&loginRequest.at(0), loginRequest.size());
}

void ServerService::logout() {
  std::vector<char> loginRequest = protocol.buildLogoutRequest();
  socket.escribir(&loginRequest.at(0), loginRequest.size());
}

/**
 *
 */
void ServerService::startScreencast(Lesson *lesson) {
  std::cout << "!!!!!!" << lesson->getId() << std::endl;

  std::vector<char> loginRequest = protocol.buildStartScreenCast(lesson);
  socket.escribir(&loginRequest.at(0), loginRequest.size());
}

void ServerService::stopListeningScreencast(Lesson *lesson) {
  std::vector<char> loginRequest = protocol.buildStopListeningScreenCast(lesson);
  socket.escribir(&loginRequest.at(0), loginRequest.size());
}

void ServerService::startAndSaveScreencast(Lesson *lesson) {
  std::vector<char> loginRequest = protocol.buildStartAndSaveScreenCast(lesson);
  socket.escribir(&loginRequest.at(0), loginRequest.size());
}

void ServerService::playScreencast(Lesson *lesson) {
  std::vector<char> loginRequest = protocol.buildPlayScreenCast(lesson);
  socket.escribir(&loginRequest.at(0), loginRequest.size());
}

/**
 *
 */
void ServerService::stopScreencast(Lesson * lesson) {
  std::vector<char> loginRequest = protocol.buildStopScreenCast(lesson);
  socket.escribir(&loginRequest.at(0), loginRequest.size());
}

/**
 *
 */
void ServerService::run() {
  while (opened) {
      Operation op;
      // Ajustar buffer size
      unsigned char buffer[30000];
      while (opened) {
          int cantidadLeidos = socket.recibir(buffer,30000);
          if (cantidadLeidos > 0) {
              op.add(buffer, cantidadLeidos);
              int i=0;
              while(op.isComplete()){
                  answerRecieved(op);
                  op.reset();
              }
          } else {
              opened = false;
          }
      }

  }
}

/**
 *
 */
void ServerService::sentChatMessage(ChatMessage* msg) {
  std::vector<char> loginRequest = protocol.buildChatMessage(msg);
  socket.escribir(&loginRequest.at(0), loginRequest.size());
}

/**
 *
 */
void ServerService::sendScreencastData(Lesson* lesson, unsigned char* data, int size,int pts) {
  Lock l(mutex);
  LOG4CXX_DEBUG(logger_, "sending screencast data " << size);
  std::vector<char> loginRequest = protocol.buildScreencastData(lesson, data, size, pts);
  LOG4CXX_TRACE(logger_, "sending to socket " << loginRequest.size() << " of bytes");
  socket.escribir(&loginRequest.at(0), loginRequest.size());
  LOG4CXX_DEBUG(logger_, "screencast data sended");
}

void ServerService::sendScreencastAudioData(Lesson* lesson, unsigned char* data, int size,int pts) {
  Lock l(mutex);
  pts=size;
  LOG4CXX_DEBUG(logger_, "sending screencast audio data " << size);
  std::vector<char> loginRequest = protocol.buildScreencastAudioData(lesson, data, size, pts);
  LOG4CXX_TRACE(logger_, "sending to socket " << loginRequest.size() << " of bytes");
  socket.escribir(&loginRequest.at(0), loginRequest.size());
}

/**
 *
 */
void ServerService::answerRecieved(Operation& op) {
  switch (op.getType()) {
  case Protocol::SCREENCAST_DATA: {
    int pts=protocol.parsePts(op);
    std::vector<char> data=op.getDataBytes(9);
    handler->handleScreencastData(data,pts);
  } break;
  case Protocol::SCREENCAST_AUDIO_DATA: {
    int pts=protocol.parsePts(op);
    std::vector<char> data=op.getDataBytes(9);
    handler->handleScreencastAudioData(data,pts);
  } break;
  case Protocol::CHAT_MESSAGE: {
    handler->handleChatMessage(protocol.parseChatMessage(op));
  } break;
  case Protocol::SCREENCAST_NOT_AVAILABLE :{
    handler->handleScreencastNotAvailable(protocol.parseLesson(op));
  } break;
  case Protocol::LOGIN_SUCCESS: {
    handler->handleLoginRequest(protocol.parseLoginMessage(op));
  } break;
  case Protocol::FIND_SHOWS: {
    std::list<Course*>* courses = new std::list<Course*>();
    std::list<Lesson*>* lessons = new std::list<Lesson*>();
    protocol.parseShows(op, *courses, *lessons);
    handler->handleFindShowsRequest(courses, lessons);
  } break;
  case Protocol::LOGIN_FAILED: {
    handler->handleLoginRequest(NULL);
  } break;
  case Protocol::START_SCREENCAST: {
    handler->handleStartScreencast(protocol.parseLesson(op));
  } break;
  case Protocol::STOP_SCREENCAST: {
    handler->handleStopScreencast(protocol.parseLesson(op));
  } break;
  }
}
